Galileo Computing < openbook > Galileo Computing - Professionelle Bücher. Auch für Einsteiger.

...powered by www.netzwerkartist.de...

 <<   zurück
Visual Basic 2005 von Andreas Kühnel
Das umfassende Handbuch
Buch: Visual Basic 2005

Visual Basic 2005
1.233 S., mit 2 CDs, 59,90 Euro
Galileo Computing
ISBN 3-89842-585-1
gp Kapitel 3 Grundlagen der Sprachsyntax
  gp 3.1 Konsolenanwendungen
    gp 3.1.1 Der Projekttyp Konsolenanwendung
    gp 3.1.2 Die Vorlage »Konsolenanwendung«
  gp 3.2 Variablen und Datentypen
    gp 3.2.1 Explizite und implizite Variablendeklaration
    gp 3.2.2 Die Variablendeklaration
    gp 3.2.3 Die einfachen Datentypen
    gp 3.2.4 Sichtbarkeit und Lebensdauer
    gp 3.2.5 Initialisierung von Variablen
    gp 3.2.6 Datentypkonvertierung
    gp 3.2.7 Ein- und Ausgabemethoden der Klasse »Console«
    gp 3.2.8 Zusammenfassung
  gp 3.3 Datenfelder (Arrays)
    gp 3.3.1 Eindimensionale Arrays
    gp 3.3.2 Mehrdimensionale Arrays
    gp 3.3.3 Ändern der Array-Kapazität
    gp 3.3.4 Initialisierung der Array-Elemente
    gp 3.3.5 Bestimmung der Array-Obergrenze
    gp 3.3.6 Zusammenfassung
  gp 3.4 Operatoren
    gp 3.4.1 Arithmetische Operatoren
    gp 3.4.2 Relationale Operatoren
    gp 3.4.3 Logische Operatoren
    gp 3.4.4 Zuweisungsoperatoren
    gp 3.4.5 Verkettungsoperator
    gp 3.4.6 Operatorprioritäten
    gp 3.4.7 Bitweise Operationen
    gp 3.4.8 Zusammenfassung
  gp 3.5 Kontrollstrukturen
    gp 3.5.1 Die If-Anweisung
    gp 3.5.2 »Select-Case«-Anweisung
    gp 3.5.3 Einzeilige Entscheidungsanweisungen
    gp 3.5.4 Zusammenfassung
  gp 3.6 Programmschleifen
    gp 3.6.1 Die For-Next-Schleife
    gp 3.6.2 Do-Loop-Schleifen
    gp 3.6.3 Die While-/End While-Schleife
    gp 3.6.4 Zusammenfassung


Galileo Computing

3.2 Variablen und Datentypen  downtop


Galileo Computing

3.2.1 Explizite und implizite Variablendeklaration  downtop

Dateninformationen bilden die Grundlage der Datenverarbeitung und hauchen einem Programm Leben ein: Daten können anwendungsspezifisch sein, den Zustand von Objekten beschreiben, Informationen aus Datenbanken repräsentieren oder auch nur eine Netzwerk- adresse. Daten bilden also gemeinhin die Basis der Gesamtfunktionalität einer Anwendung.

Praktisch jedes Programm benötigt Daten, um bestimmte Aufgaben zu erfüllen. Daten werden in Variablen vorgehalten. Dabei steht eine Variable für eine Adresse im Hauptspeicher des Rechners. Ausgehend von dieser Adresse wird eine bestimmte Anzahl von Bytes reserviert – entsprechend dem Typ des Werts. Das, was eine Variable repräsentiert, kann vielfältiger Art sein: eine einfache Zahl, eine große Fließkommazahl, ein einzelnes Zeichen, eine Zeichenkette, eine Datums- oder Zeitangabe, aber auch die Referenz auf die Startadresse eines Objekts.

Der Variablenname, auch Bezeichner genannt, dient dazu, die Speicheradresse im Programmcode mit einem einfach zu merkenden Namen anzusprechen. Er ist also vom Wesen her nichts anderes als ein Synonym oder Platzhalter einer bestimmten Speicherlokalität.

Variablen sollten immer deklariert werden. Unter einer Variablendeklaration wird die Bekanntgabe des Namens der Variablen sowie des von ihr repräsentierten Datentyps verstanden. Dies ist der Standard unter Visual Basic 2005 und wird deshalb auch als explizite Deklaration bezeichnet.

Eine Deklaration muss vor der ersten Wertzuweisung an die Variable erfolgen und könnte beispielsweise folgendermaßen aussehen:


Dim intVar As Integer

Damit wird dem Compiler mitgeteilt, dass der Bezeichner intVar für ein Datum steht, das vom Typ einer Ganzzahl, genauer gesagt vom Typ Integer ist und einen bestimmten Wertebereich abdecken kann. Wir werden auf die Details der Deklaration später noch einmal zurückkommen. Mit


intVar = 1000

wird dieser Variablen die Zahl 1000 zugewiesen.

Im Gegensatz zu den meisten anderen Programmiersprachen hat der Entwickler unter Visual Basic 2005 die Entscheidungsfreiheit, die standardmäßig vorgegebene explizite Variablendeklaration abzuschalten und stattdessen mit der impliziten Deklaration zu arbeiten. Implizit bedeutet, dass eine Variable nicht bekannt gegeben werden muss einem Bezeichner kann ein Wert ohne vorherige Deklaration zugewiesen werden. Dazu dient die Compiler-Einstellung Option Explicit, die nur zwei Zustände kennt: On (= explizite Deklaration) und Off (= implizite Deklaration). Die anwendungsweite, vom Standard abweichende Vorgabe kann im Projekteigenschaftsfenster eingestellt werden. Dieses öffnen Sie durch Doppelklicken auf den Knoten My Project im Projektmappen-Explorer. Anschließend öffnen Sie die Registerkarte Kompilieren und legen die Compiler-Einstellung Option Explicit entsprechend fest.

Abbildung
Hier klicken, um das Bild zu Vergrößern

Abbildung 3.2     Die Compiler-Einstellungen im Projekteigenschaftsfenster

In jeder Quellcodedatei kann eine von der anwendungsweiten Vorgabe abweichende Einstellung gewählt werden. Dazu wird außerhalb des Moduls die Option Explicit-Anweisung gesetzt. Mit


Option Explicit Off
Module Module1
Sub Main()
myVariable = 1045
End Sub
End Module

wird demzufolge die explizite Variablendeklaration abgeschaltet und die implizite Deklaration zugelassen. Daher ist die Zuweisung von 1045 an die Variable myVariable syntaktisch korrekt. Ohne die Option Explicit-Anweisung würde die Entwicklungsumgebung einen Syntaxfehler melden.

Bei der impliziten Deklaration ist der Typ des Werts, der von der Variablen beschrieben wird, nicht bekannt. Es könnte sich um eine Ganzzahl, eine Dezimalzahl oder eine Zeichenkette handeln – um nur einige der Möglichkeiten zu nennen. Trotzdem wird für eine implizit deklarierte Variable natürlich in gleicher Weise wie für eine explizit deklarierte Variable Speicher reserviert. Dabei muss der Variablen intern ein Datentyp zugeordnet werden, der alle denkbaren Informationen aufzunehmen in der Lage ist: Es handelt sich um den Datentyp Object, auf den wir weiter unten noch eingehen werden.

Explizit oder implizit deklarieren?

Es stellt sich an dieser Stelle die Frage, welche Vorteile die eine oder andere Deklarationsvariante hat und welche Konsequenzen daraus folgen. Angenommen, Sie sind schreibfaul und verzichten auf die explizite Deklaration. Im Code wollen Sie einer Variablen namens myUndeclaredVar einen Wert zuweisen und diesen an der Konsole ausgeben lassen. Dazu sieht der Programmcode wie folgt aus:


Option Explicit Off
Module Module1
Sub Main()
myVar = 10
Console.WriteLine("Wert = {0}", yVar)
End Sub
End Module

Dieses erste lauffähige Codefragment wollen wir auch dazu benutzen, um es zu analysieren.

Ausführbarer Programmcode kann nur innerhalb einer Prozedur geschrieben werden. In diesem einfachen Beispiel dient dazu die Main-Prozedur, deren Prozedurrahmen bei der Erstellung eines neuen Projekts vom Typ einer Konsolenanwendung automatisch erzeugt wird. Eine Prozedurdefinition wird eingeleitet mit dem Schlüsselwort Sub unter Angabe des Prozedurnamens:


Sub Main()

Das erforderliche Klammerpaar hinter dem Prozedurnamen kann eine Parameterliste enthalten und braucht uns an dieser Stelle noch nicht zu interessieren. Mit


End Sub

wird der Anweisungsblock einer Prozedur abgeschlossen.

In Main wird zunächst der Variablen myVar der Wert 10 zugewiesen. Da auf Modulebene Option Explicit Off gesetzt ist, muss die Variable nicht deklariert werden. In der danach folgenden Codezeile soll der zugewiesene Inhalt an der Konsole ausgegeben werden. Dazu wird die Methode WriteLine des Console-Objekts aufgerufen. Diese Methode stellt dem Entwickler eine Vielzahl von Ausgabemöglichkeiten zur Verfügung. In unserem Beispiel wird im Klammerpaar zunächst eine Zeichenfolge in Anführungsstrichen festgelegt, gefolgt vom Namen einer Dateninformation in Form einer Variablen, die durch ein Komma von der Zeichenfolge getrennt wird. Seltsam sieht im ersten Augenblick {0} innerhalb der Zeichenfolge an. Hierbei handelt es sich um eine Art Platzhalter, der bei der Ausgabe an der Konsole durch den Inhalt der Variablen ersetzt wird.

An dieser Stelle kommen Sie zum ersten Mal in Kontakt mit Klassen, Objekten und deren Methoden. Console ist ein solches Objekt – präziser gesagt handelt es sich dabei um eine Klassendefinition, aber dieser Unterschied spielt für uns derzeit noch keine Rolle. Das Verhalten von Objekten wird durch Methoden beschrieben, so wie im Fall von Console durch WriteLine zur Ausgabe im Eingabefenster. Es ist allgemein übliche Syntax, die Methode eines Objekts durch Punktnotation aufzurufen. Dazu wird zuerst der Objektname genannt und anschließend durch einen Punkt als Trennsymbol separiert die Methode. In unserem Beispiel also:


Console.WriteLine(...)

Das Codefragment des obigen Beispiels reicht bereits vollkommen aus, um das Programm problemlos auszuführen zu können. Um die Laufzeit aus der Entwicklungsumgebung heraus zu starten und den Programmcode zu testen, haben Sie drei Möglichkeiten:

gp  Sie klicken die Starten-Schaltfläche in der Symbolleiste.
gp  Sie wählen den Menüpunkt Debuggen N Starten.
gp  Sie drücken die F5-Taste.

Die Konsole öffnet sich daraufhin kurz und wird anschließend sofort wieder geschlossen. Um diesen Effekt zu vermeiden, müssen wir eine dritte Anweisung in das Codefragment hinter der Anweisung zur Konsolenausgabe einfügen:


Sub Main()
myVar = 10
Console.WriteLine("Wert = {0}", yVar)
Console.ReadLine()
End Sub

ReadLine ist ebenfalls eine Methode von Console. Sie wartet auf die Eingabe des Anwenders und setzt erst dann den Programmfluss fort, wenn die Eingabe mit dem Drücken der (Enter)-Taste abgeschlossen wird. Durch die Ergänzung des Codes mit der ReadLine-Methode verhindern wir folglich das sofortige Schließen des Konsolenfensters. In allen Anwendungen, die auf der Konsole basieren, wird dieser Methodenaufruf daher zukünftig grundsätzlich als letzte Anweisung stehen.

Kommen wir zurück zur impliziten Variablendeklaration unseres Programmcodebeispiels. Zur Verdeutlichung der Problematik der impliziten Deklaration entspricht der Variablenname in der ausgebenden zweiten Codezeile nicht dem der Variablen, der eine Zeile vorher ein Wert zugewiesen wurde: Beide Bezeichner unterscheiden sich, der eine lautet myVar, der andere yVar! Ein angenommener, unbeabsichtigter Tippfehler, von dem sich keiner freisprechen kann, denn eigentlich soll an der Konsole myVar ausgegeben werden.

Führen Sie das Programm aus, wird an der Eingabeaufforderung die folgende Ausgabe erscheinen:


Wert =

Dass sich beide Bezeichner unterscheiden, interessiert den Compiler nicht im Geringsten. Er nimmt keine Notiz davon, denn die explizite Variablendeklaration ist zugunsten der impliziten deaktiviert. Was macht der Compiler nun? Ganz einfach, er interpretiert den falsch geschriebenen Variablennamen als zweite Variable, deren Inhalt dann an der Konsole entsprechend ausgegeben wird – er ist leer!

Dieses Problem, das in einer Anwendung zu sehr schwer lokalisierbaren Fehlern führt, kann mit der expliziten Deklaration vermieden werden. Beachten Sie dabei bitte, dass der Option Explicit-Schalter im Projekteigenschaftsfenster nun auf seiner Standardeinstellung On steht.


Module Module1
Sub Main()
'Deklaration der Variablen myDeclaredVar
Dim myDeclaredVar As Integer
myDeclaredVar = 10
Console.WriteLine("Wert = {0}", myDeclaredVar)
Console.Read()
End Sub
End Module

Ein versehentlich falsch geschriebener Variablenname in der Ausgabezeile würde nun zu einem sofortigen Hinweis der Entwicklungsumgebung führen (blaue Schlangenlinie unterhalb des falsch geschriebenen Namens), da bereits zur Entwicklungszeit eine syntaktische Überprüfung erfolgt.

Anweisungen

In Visual Basic 2005 wird der Zeilenumbruch als Anweisungsende interpretiert. Sie haben aber auch die Möglichkeit, zwei oder mehr Anweisungen in eine Zeile zu schreiben. Dazu müssen beide Anweisungen nur durch einen Doppelpunkt getrennt werden, z.  B.:


Sub Main()
Dim intVar As Integer : intVar = 10
Console.WriteLine("Wert = {0}", intVar) : Console.ReadLine()
End Sub

In diesem Codefragment sind die Anweisung zur Ausgabe an der Konsole und die Anweisung, die das sofortige Schließen des Eingabefensters unterbindet, in einer Zeile implementiert.

Andererseits können Anweisungen, Definitionen und Deklarationen in Visual Basic sehr lang werden und die Breite des Texteditors deutlich übertreffen. Das dann notwendige Scrollen mit dem horizontalen Rollbalken ist der Nachteil, der für die generell gute Lesbarkeit des Visual Basic-Programmcodes in Kauf genommen werden muss.

Wollen Sie dennoch den gesamten Code mit einem Blick erfassen, können Sie eine überlange Anweisungszeile in zwei oder noch mehr Zeilen aufsplitten. Dazu wird der Unterstrich als Verbindungszeichen der aufgesplitteten Codezeile eingesetzt. Bedingung ist dabei nur, dass:

gp  in der Anweisung vor dem Unterstrich ein Leerzeichen steht
gp  der Zeilenumbruch nicht mitten in einer Zeichenfolge erfolgt

Mit diesen beiden Regeln wären beispielsweise die folgenden Umbrüche syntaktisch korrekt:


Dim myDeclaredVar _
As Integer
Console.WriteLine("Wert = {0}", _
myDeclaredVar)

Der folgende Zeilenumbruch hingegen ist falsch, da er mitten in einer Zeichenfolge erfolgt:


Console.WriteLine("Wert _
= {0}", myDeclaredVar)

Kommentare

Sie sollten nicht mit Kommentaren geizen. Kommentare helfen, den Programmcode der Anwendung besser zu verstehen. Sie tun nicht nur anderen damit einen Gefallen, die sich mit Ihrem Code auseinander setzen müssen, sondern auch sich selbst. Wenn Sie bereits programmiert haben, werden Sie wissen, wie schwierig es ist, nach dem dreiwöchigen Mallorca-Urlaub wieder den eigenen Code zu verstehen. Was beschreibt diese Variable, welche Funktionalität steckt hinter jener Methode? Ersparen Sie sich und anderen die unnötige und zeitraubende Suche nach den Antworten.

Kommentare werden in Visual Basic mit einem Hochkomma (Apostroph) eingeleitet. Sie gelten dann für den gesamten Rest der Codezeile:


' dies ist ein Kommentar

Bei größeren Kommentarblöcken kann es recht nervend sein, vor jede Zeile explizit das Hochkomma zu setzen. Um sich die Arbeit zu erleichtern, können Sie die Entwicklungsumgebung durch eine weitere Symbolleiste ergänzen, die eine unterstützende Alternative anbietet. Dazu brauchen Sie nur mit der rechten Maustaste das Kontextmenü der aktuellen Symbolleiste zu öffnen. In diesem Kontextmenü finden Sie alle Symbolleisten des Visual Studios, die nach Bedarf ein- oder ausgeblendet werden können. Aus dem vielfältigen Angebot wählen Sie Text-Editor. In der neu hinzugefügten Symbolleiste befindet sich eine Schaltfläche, die das Auskommentieren größerer, im Texteditor markierter Codeblöcke ermöglicht, und eine weitere, mit der diese Kommentierung auch schnell wieder aufgehoben werden kann (siehe auch Abbildung 3.3).

Abbildung
Hier klicken, um das Bild zu Vergrößern

Abbildung 3.3     Die Symbolleiste »Text-Editor«

In der Entwicklungsumgebung erscheinen Kommentare in einer anderen Schriftfarbe als der Programmcode selbst. Sie können die Farbgebung ganz individuell festlegen, wenn Sie das Menü Extras öffnen und hier den Punkt Optionen wählen. Wählen Sie im Knoten Umgebung der linken Liste Schriftarten und Farben aus. Rechts neben dem Listenfeld bieten sich anschließend mehrere Optionen, die Darstellung des Programmcodes im Codefenster zu beeinflussen.


Galileo Computing

3.2.2 Die Variablendeklaration  downtop

Eine Variablendeklaration setzt sich immer aus drei Informationen zusammen:

gp  einem Zugriffsmodifizierer, der die Lebensdauer, Sichtbarkeit und somit den Zugriff auf die Variable beeinflusst
gp  dem Variablennamen, auch Bezeichner genannt
gp  dem Datentypen, den die Variable repräsentiert

Die allgemeine Syntax zur Deklaration einer Variablen lautet wie folgt:


<Zugriffsmodifizierer> <Bezeichner> [As <Datentyp>]

Variablen zu deklarieren heißt, einem Bezeichner mit der As-Klausel einen bestimmten Datentypen zuzuordnen. Die Angabe des Datentyps ist optional und hängt vom Optionsschalter Option Strict ab. Dieser Schalter kann, wie auch schon der Schalter Option Explicit, entweder im Projekteigenschaftsfenster gesetzt werden (siehe dazu auch die Abbildung 3.2) oder mit


Option Strict On|Off

außerhalb eines Moduls. Die Standardeinstellung ist Off. Dies hat zur Folge, dass die As-Klausel bei einer Variablendeklaration nicht angegeben werden muss:


Dim myVar

Die Schalterstellung hat zudem einen entscheidenden Einfluss auf die Typkonvertierung, mit der wir uns weiter unten in diesem Kapitel noch beschäftigen werden.

In einer Codezeile können durchaus mehrere Variablen deklariert werden. Außerdem kann eine Variable schon bei der Deklaration initialisiert, ihr also ein spezifischer Startwert zugewiesen werden.


' x, y und z sind vom Typ Integer
Public x, y, z As Integer
' x ist vom Typ Short, y vom Typ String
Dim x As Short, y As String
' strText wird als String deklariert und sofort mit der
' Zeichenfolge "Hallo Welt" initialisiert
Dim strText As String = "Hallo Welt"
' die Variable iVar wird deklariert und ihr wird das Datum 12
' zugewiesen, dblGehalt ist vom Typ Double
Dim iVar As Integer = 12, dblGehalt As Double

Der Variablenname

Der Variablenname (Bezeichner) kann nahezu beliebig festgelegt werden, unterliegt aber besonderen Reglementierungen:

gp  Ein Bezeichner darf sich nur aus alphanumerischen Zeichen und dem Unterstrich zusammensetzen. Leerzeichen und andere Sonderzeichen wie beispielsweise #, §, $ usw. sind nicht zugelassen.
gp  Ein Bezeichner muss mit einem Buchstaben oder dem Unterstrich anfangen.
gp  Ein allein stehender Unterstrich als Variablenname ist nicht zulässig.
gp  Der Bezeichner muss eindeutig sein. Er darf nicht gleich lautend mit einem Schlüsselwort, einer Prozedur, einer Klasse oder einem Objektnamen sein.

Die letzte Regel lässt sich mit einem kleinen Trick umgehen. Wenn Sie beispielsweise – aus welchen Gründen auch immer – einer Variablen den Namen des von VB 2005 reservierten Schlüsselworts Public geben wollen, können Sie diesen Bezeichner in eckige Klammern setzen:


Dim [Public] As Integer
[Public] = 10

Mit der Klammerung wird die Beziehung außer Kraft gesetzt. Inwieweit dies von praktischem Nutzen ist, mögen Sie selbst entscheiden.

Zur Verdeutlichung dieser Regeln einige Beispiele:


' korrekte Variablendeklarationen
Dim lngMyVar As Long
Dim bResult_12 As Byte
Dim intCarColor As Integer
' fehlerhafte Variablendeklarationen
Dim 34M As Integer
Dim strMessage Text As String
Dim lngSalary%Tom as Integer

VB 2005 unterscheidet nicht zwischen der Groß- und Kleinschreibung wie die meisten anderen Programmiersprachen. Dennoch wird der Groß-/Kleinschreibung im Texteditor Rechnung getragen. Ausschlaggebend ist die Angabe in der Deklaration. Sie können sich dies sogar zunutze machen, wenn Sie bei der Deklaration einer Variablen dem Bezeichner einen oder mehrere Großbuchstaben mit auf den Lebensweg geben, z.  B.:


Dim meineVariable As Integer

Weisen Sie im Laufe des weiteren Programmierens der Variablen einen Wert zu und schreiben den Namen dabei nur in Kleinbuchstaben, beispielsweise


meinevariable = 10

wird die Entwicklungsumgebung beim Zeilenumbruch automatisch die deklarierte Schreibweise erkennen und entsprechend in


meineVariable = 10

korrigieren. Mit dieser Technik können Sie sofort erkennen, ob Sie den Namen der Variablen richtig geschrieben haben, und mögliche lästige Fehlermeldungen beim späteren Testen vermeiden.

Noch ein Hinweis zur Namensvergabe: Wählen Sie grundsätzlich beschreibende Namen, damit Ihr Code später besser lesbar wird. Einfache Bezeichner wie x oder y usw. sind wenig aussagefähig. Besser wäre eine Wahl wie intFarbe, dblGehalt, strVorname usw. Nur den Zählervariablen von Schleifen werden meistens Kurznamen gegeben.

Empfehlenswerterweise sollten die Bezeichner von Variablen mit einem Kleinbuchstaben anfangen – im Gegensatz zu den Namen von Prozeduren und Objekten. Sie können dazu ein Präfix benutzen, aus dem auch innerhalb einer Anweisung hervorgeht, welcher Datentyp von der Variablen beschrieben wird:


Dim intVar As Integer
Dim strText As String

Die Verwendung eines Präfixes zusammen mit einem sinnvollen, beschreibenden Bezeichner macht den Programmcode lesbarer. Zusammen mit einer sauberen Strukturierung durch Einzüge und mit ausreichenden Kommentaren versehen wird auch eine dritte Person kaum Schwierigkeiten haben, in angemessener Zeit die Programmlogik zu interpretieren.

Die folgende Tabelle 3.1 enthält die Präfixe für die verschiedenen Datentypen von VB 2005, die als Vorschläge gedacht sind.


Tabelle 3.1     Präfixvorschläge für Datentypen

Datentyp Präfix
Short srt
Integer int
Long lng
Single sng
Double dbl
Decimal dec
Char chr
String str
Boolean bln
Byte bt
Date dt
Object obj

Der Datentyp

Mit dem Datentyp wird festgelegt, wie groß der Wertebereich der zu speichernden Dateninformation sein soll, wie viel Speicherplatz dafür reserviert werden muss und, letztendlich damit auch, wie dieser Speicherplatz zur Laufzeit interpretiert wird. Weiter unten in Abschnitt 3.2.3 werden alle zur Verfügung stehenden Datentypen erläutert.

gp  Die Datentypen lassen sich in zwei Gruppen einteilen:
gp  native Typen, wie beispielsweise Integer oder Decimal
gp  Objekttypen

In diesem Kapitel werden Sie nur die nativen Datentypen kennen lernen, mit den anderen werden wir uns ab Kapitel 4 auseinander setzen.

Eine weitere Gruppierung der Datentypen erfolgt nach:

gp  Wertetypen
gp  Referenztypen

Werte- bzw. Referenztypen beschreiben, wie die Daten im Speicher vorgehalten werden und wie mit ihnen gearbeitet wird. Die meisten nativen Datentypen gelten unter .NET als Wertetypen, die auf Klassendefinitionen basierenden Objekte als Referenztypen. Die Ausnahmen sind die Typen Object und String, die zwar den nativen Datentypen zugerechnet werden können, ihrem Wesen nach aber Referenztypen sind. Obwohl die Begriffe Objekt, Referenz- und Wertetyp in den folgenden Abschnitten noch öfters fallen werden, wird die genaue Erklärung erst in Kapitel 4 erfolgen, wenn wir uns intensiv mit Klassen und Objekten beschäftigen.

Die Zugriffsmodifizierer

Die Schlüsselwörter Dim, Static, Public und Private beschreiben die Sichtbarkeit und Lebensdauer einer Variablen und werden als Zugriffsmodifizierer bezeichnet. Sie können bei der Deklaration nur einen Zugriffsmodifizierer angeben. Über die Bedeutung der Einzelnen werden Sie weiter unten in diesem Abschnitt alles Weitere erfahren.


Galileo Computing

3.2.3 Die einfachen Datentypen  downtop

Die .NET-Laufzeitumgebung verfolgt das Konzept der Objektorientierung nach strengen Maßstäben. Selbst einfache Datentypen werden als Objekte angesehen, die Methoden bereitstellen, um mit einer Variablen bestimmte Aktionen auszuführen. In der Tabelle 3.2 sind alle nativen Datentypen zusammenfassend aufgeführt.


Tabelle 3.2     Die elementarsten Datentypen

.NET-Laufzeittyp VB -Alias CLS-kompatibel Wertebereich
Byte Byte ja 0 bis 255
SByte SByte nein –128 ... 127
Int16 Short ja –215 . 215  – 1
UInt16 UShort nein 0 . 65535
Int32 Integer ja –231  . 231  – 1

UInt32

UInteger nein 0 ... 232  – 1
Int64 Long ja –263  . 263  – 1
UInt64 ULong nein 0 . 264  – 1
Single Single ja 1,4*10   –     45  bis 3,4*1038 
Double Double ja 5,0*10   –     324  bis 1,7*10308 
Decimal Decimal ja +/–79E27 ohne Dezimalpunktangabe; +/–7.9E-29, falls 28 Stellen hinter dem Dezimalpunkt angegeben werden. Die kleinste darstellbare Zahl beträgt +/–1.0E-29
Char Char ja Unicode-Zeichen zwischen 0 und 65535
String String ja ca. 231  Unicode-Zeichen
Boolean Boolean ja True oder False
Object Object ja Eine Variable vom Typ Object kann jeden anderen Datentypen enthalten, ist also universell.

In der ersten Spalte ist der Typbezeichner in der .NET-Klassenbibliothek angeführt, in der zweiten Spalte der VB-Alias, der bei der Deklaration einer Variablen dieses Typs angegeben werden kann.

Zu den Angaben in der dritten Spalte muss ich Ihnen eine Erklärung geben. .NET verfolgt nicht nur ein plattformunabhängiges Konzept, sondern auch ein sprachunabhängiges. Das bedeutet, dass eine Komponente, die in einer fiktiven .NET-Programmiersprache A geschrieben wird, auch den vollen Zugriff auf alle Features einer Komponente haben sollte, die in einer anderen .NET-Sprache, nennen wir sie hier der Einfachheit halber B, implementiert ist.

Das kann nur problemlos funktionieren, wenn sich beide auf einen gemeinsamen Nenner hinsichtlich der Sprachfeatures geeignet haben, zu denen auch die elementaren Datentypen zu rechnen sind. Dieser gemeinsame Nenner wird durch die Common Language Specification (CLS) vorgegeben. Das bedeutet, wenn eine .NET-Anwendung CLS-konform codiert wird, ist eine Garantie damit verbunden, dass jeder andere .NET-Code Zugriff auf die (öffentlichen) Komponenten der CLS-konformen Anwendung hat – unabhängig davon, in welcher Sprache sie codiert ist.

Wie Sie sehen, sind nicht alle Datentypen der Tabelle 3.2 CLS-konform. Sie können diese zwar innerhalb Ihrer Anwendung problemlos einsetzen, aber in der öffentlichen Schnittstelle haben sie nichts zu suchen.

Wie der Tabelle zu entnehmen ist, basieren alle Typen auf einer Klassendefinition im .NET-Framework. Das hat zur Folge, dass anstelle der Angabe des C#-Alias zur Typbeschreibung auch der .NET-Laufzeittyp genannt werden kann. Damit sind die beiden folgenden Deklarationen der Variablen intVar absolut gleichwertig:


Dim intVar As Integer
Dim intVar As Int32

Ganzzahlige Datentypen

VB 2005 stellt acht ganzzahlige Datentypen zur Verfügung, von denen vier vorzeichenbehaftet sind, der Rest nicht. Die uns interessierenden CLS-konformen sind

gp  Byte
gp  Int16
gp  Int32
gp  Int64

Int16, Int32 und Int64 haben einen Wertebereich, der nahezu gleichmäßig über die negative und positive Skala verteilt ist. Die vorzeichenlosen Datentypen, zu denen auch Byte gehört, decken hingegen nur den positiven Wertebereich, beginnend bei 0, ab. Der vorzeichenlose Typ Byte, der im Gegensatz zu SByte CLS-konform ist, ist insbesondere dann von Interesse, wenn auf binäre Daten zugegriffen wird.

Ganzzahlige Literale können in Dezimal-, Hexadezimal- oder Oktalform übergeben werden. Hexadezimale Zahlen (Basis = 16) erhalten das Präfix &H, oktale (Basis = 8) das Präfix &O. Die folgenden Zahlen beschreiben beide dieselbe Dezimalzahl, nämlich 225, zuerst in hexadezimaler, danach in oktaler Schreibweise:


Dim intHex As Integer = &HE1
Dim intOct As Integer = &O341

Fließkommazahlen

Single, Double und Decimal sind die drei Typen, mit denen unter Visual Basic Fließkommazahlen dargestellt werden können. Sie beschreiben nicht nur unterschiedliche Wertebereiche, sondern auch – was noch viel wichtiger ist – unterschiedliche Genauigkeiten. Auf herkömmlichen Systemen beträgt die Genauigkeit eines Single-Typs etwa zehn Stellen, der eines Double-Typs etwa 16 Stellen. Abhängig ist die Genauigkeit dabei immer von der Anzahl der Ziffern des ganzzahligen Anteils der Dezimalzahl.

Das folgende Codefragment demonstriert die Genauigkeit, die mit einem Single erreicht werden kann.


' --------------------------------------------------------
' Beispiel: ...\Kapitel 3\DezGenauigkeit
' --------------------------------------------------------
Module Module1
Sub Main()
Dim x, y As Single
x = 0.123456789
y = 0.1234567891
If x = y Then
Console.WriteLine("Beide Werte sind gleich.")
Else
Console.WriteLine("Beide Werte sind ungleich.")
End If
Console.ReadLine()
End Sub
End Module

Es werden zunächst zwei Variablen vom Typ Single deklariert und beiden danach ein Wert zugewiesen, der sich nur an der zehnten Nachkommastelle unterscheidet. Mit der Anweisung If...End If werden die Inhalte beider Variablen auf Gleichheit überprüft. Entspricht der von x repräsentierte Wert dem von y, soll die Meldung »Beide Werte sind gleich« ausgegeben werden, weichen die Variableninhalte voneinander ab, sollte die Ausgabe »Beide Werte sind ungleich« lauten.

Erstaunlicherweise erscheint nach dem Start der Laufzeit die Meldung mit der Aussage, die von den beiden Variablen beschriebenen Werte seien gleich. Diese offensichtliche Falschaussage ist darauf zurückzuführen, dass ein Single-Typ nicht in der Lage ist, alle im vorliegenden Fall angegebenen Nachkommastellen exakt zu interpretieren – er ist schlichtweg überfordert. Für Berechnungen, die eine höhere Genauigkeit erfordern, ist dieser Datentyp daher weniger gut geeignet.

Ein ähnlicher Test – diesmal mit einem Double – führt zu demselben Ergebnis. Allerdings kann die Anzahl der Nachkommastellen unter Beibehaltung der Genauigkeit erhöht werden. Dies ist auch meistens der Grund dafür ist, sich für den einen oder anderen Datentypen zu entscheiden – die Größenordnung, die ein Single darstellen kann, ist per Definition bereits so groß, dass hier weniger das Entscheidungskriterium zu suchen ist, die Frage ist nur: Reicht die Genauigkeit für die Berechnung aus?

Wenn von der Genauigkeit von Fließkommazahlen gesprochen wird, bedeutet das nicht, dass die Genauigkeit auf den Dezimalteil bezogen wird. Vielmehr ist es die Genauigkeit, mit der beispielsweise beim Single die ersten zehn Zahlen – beginnend links mit der ersten – unterschieden werden können. Um dies zu testen, brauchen Sie nur die beiden Literale des vorhergehenden Beispiels zu ändern, z.  B.:


Sub Main()
Dim x, y As Single
x = 10.123456
y = 10.1234567891
If x = y Then
Console.WriteLine("Beide Werte sind gleich.")
Else
Console.WriteLine("Beide Werte sind ungleich.")
End If
Console.ReadLine()
End Sub

Wenn Sie diesen Code laufen lassen, werden Sie die folgende Ausgabe erhalten:


Beide Werte sind ungleich.

Hängen Sie die Zahl 7 als letzte Nachkommastelle an die Variable x an, also


x = 10.1234567

sieht der Compiler beide Variableninhalt als gleich an. Er berücksichtigt demnach die achte Nachkommastelle nicht mehr für den Vergleich.

Der Forderung nach sehr hoher Genauigkeit einer Dezimalzahl können die beiden Datentypen Single und Double oft nicht ausreichend erfüllen. Bei höheren Ansprüchen muss die Wahl auf einen anderen, passenderen Datentypen fallen: Decimal. Decimal kann Zahlen darstellen, die bis zu 28 Nachkommastellen aufweisen. Je mehr Nachkommastellen eine Zahl hat, desto höher ist auch die Genauigkeit, mit der Operationen ausgeführt werden können. Mit steigender Genauigkeit verringert sich andererseits jedoch auch der darstellbare Wertebereich.

Während die Zuweisung eines ganzzahligen Literals an ein Decimal in bekannter Art und Weise erfolgt, also beispielsweise mit


Dim decA As Decimal
decA = 120

muss bei der Zuweisung einer numerischen Zahl mit großem Dezimalanteil ein kleiner Trick angewandt werden. Wenn Sie im Texteditor beispielsweise


decA = 0.1234567890123456789012

eingeben, wird ihre Eingabe nach dem Zeilenumbruch in


decA = 0.123456789012346

eingekürzt. Im ersten Moment erscheint dies unverständlich und wenig plausibel, die Erklärung ist allerdings recht einfach. Zur Laufzeit der Anwendung muss einem Literal wie jedem anderen Datum auch ein Speicherplatz zugewiesen werden. Dabei wird

gp  ein ganzzahliges Literal als Integer interpretiert,
gp  ein Literal vom Typ einer Dezimalzahl als Double.

Nach den Gesetzen der Typkonvertierung, die wir in Abschnitt 3.2.6 behandeln werden, kann einer Zahl vom Typ Integer einem Decimal-Wert zugewiesen werden, ohne dass es zu einem Datenverlust kommt. Der Integer wird implizit in Decimal konvertiert. Dieselbe Aussage gilt allerdings nicht, wenn ein Double einem Decimal zugewiesen werden soll – es kommt zu einer Fehlermeldung in der Entwicklungsumgebung. Dieses Verhalten kann durch das Anhängen des Buchstabens »D« vermieden werden:


decA = 0.1234567890123456789012D

Dieses Verhalten gilt nur, wenn der Schalter Option Strict On gesetzt ist.

Betrachten wir nun zum Abschluss noch einmal beispielhaft die Aufteilung der darstellbaren 28 Zahlen eines Decimal-Typen in den ganzzahligen und dezimalen Anteil.


decA = 0.1234567890123456789012345678D

decA wird ein Literal mit 28 Nachkommastellen zugewiesen. Geben Sie eine noch genauere Zahl an, wird der unakzeptable Teil von der Entwicklungsumgebung automatisch abgeschnitten.

Wir wollen nun die Genauigkeit testen, mit welcher der Datentyp Decimal zu arbeiten in der Lage ist. Dazu dient uns der folgende Code:


' ---------------------------------------------------------------
' Beispiel: ...\Kapitel 3\DecimalVergleich
' ---------------------------------------------------------------
Module Module1
Sub Main()
Dim x, y, z As Decimal
x = 0.1234567890123456789012345678D
y = 0.1234567890123456789012345678D
z = 0.1234567890123456789012345679D
'Vergleich der beiden Variablen x und y
If x = y Then
Console.WriteLine("x und y sind gleich.")
Else
Console.WriteLine("x und y sind ungleich.")
End If
'Vergleich der beiden Variablen x und z
If x = z Then
Console.WriteLine("x und z sind gleich.")
Else
Console.WriteLine("x und z sind ungleich.")
End If
Console.ReadLine()
End Sub
End Module

Beachten Sie, dass die beiden Variablen x und y identisch sind, während sich x und z in der 28. Nachkommastelle unterscheiden. Lassen Sie das Programm laufen, wird an der Konsole folgende Ausgabe angezeigt.


x und y sind gleich.
x und z sind ungleich.

Die Laufzeit erkennt den Unterschied an der 28. Nachkommastelle, was uns das Ergebnis der Anzeige beweist. Das ist natürlich eine deutliche Steigerung gegenüber den beiden anderen Typen Single und Double.

Wird der ganzzahlige Anteil eines Decimals vergrößert, z.  B.:


decA = 1000.1234567890123456789012346D

bewirkt jede weitere Ziffer links vom Komma einen Verlust an Genauigkeit, im Beispiel von decA weist der Dezimalteil nur noch eine Genauigkeit von 25 Stellen rechts vom Komma auf.

Genau genommen wird die letzte Ziffer einer Fließkommazahl eines Decimal-Typs schon dann abgeschnitten, wenn der ganzzahlige Anteil größer 7 ist.


Hinweis

Beachten Sie, dass der ganzzahlige Anteil einer Fließkommazahl grundsätzlich immer durch einen Punkt vom Nachkommaanteil getrennt wird. Diese Regel gilt auch dann, wenn Sie in der spezifischen Ländereinstellung auf Systemebene ein Komma als Trennzeichen eingestellt haben.


Zeichenbasierte Datentypen

Variablen vom Typ Char können ein Zeichen des Unicode-Zeichensatzes aufnehmen. Unicode ist die Erweiterung des 1 Byte großen ASCII- bzw. ANSI-Zeichensatzes mit seinen insgesamt 256 verschiedenen Zeichen. Unicode berücksichtigt die Bedürfnisse außereuropäischer Zeichensätze – z.  B. das japanische Kanji –, für die eine 1-Byte-Codierung nicht ausreichend ist. Jedes Unicode-Zeichen beansprucht 2 Byte, folglich ist der Unicode-Zeichensatz auch auf 65536 Zeichen beschränkt. Die ersten 128 Zeichen (0 – 127) entsprechen denen des ANSI-Zeichensatzes, die folgenden 128 Zeichen beinhalten unter anderem Sonderzeichen und Währungssymbole.


Dim chrZeichen As Char = "A"

Das funktioniert allerdings nur, wenn Option Strict ausgeschaltet ist (Off). Für den Fall, dass Sie diesen Schalter gesetzt haben (On), muss die Zuweisung eines Zeichens an die Char-Variable umgewandelt werden. Das können Sie entweder über die Konvertierungsfunktion CChar oder über das Anhängen des Typkennzeichens C erreichen.


Dim c As Char
'Anhängen des Typkennzeichens C
c = "A"C
'Konvertierungsfunktion CChar
c = CChar("A")

Versuchen Sie, einer Char-Variablen mehr als ein Zeichen zuzuweisen, ist nur das erste ausschlaggebend.

Der Typ Char beschränkt sich nur auf ein Zeichen. Um eine Zeichenkette, die sich aus keinem oder bis zu maximal ungefähr 231  Einzelzeichen zusammensetzt, zu speichern oder zu bearbeiten, deklarieren Sie eine Variable vom Datentyp String. Die Einzelzeichen werden dabei wie ein Char-Typ als Unicode-Zeichen der Größe 16 Bit behandelt. Zeichenketten werden grundsätzlich in Anführungsstriche gesetzt.


Dim str As String = "VB.NET macht Spass!"

Die Länge einer Stringvariablen ist dynamisch und passt sich der Länge der zugewiesenen Zeichenfolge an.

Weitere Datentypen

Variablen vom Typ Boolean können nur zwei Zustände beschreiben, nämlich True oder False.

In vielen Programmiersprachen wird False numerisch mit 0 beschrieben, True durch alle Werte, die von 0 abweichen. .NET ist hier sehr viel strenger. Hier ist True nicht 1 und auch nicht 67, sondern ganz schlicht True. Aus diesem Grund ist auch die folgende Anweisung falsch, die so in anderen Programmiersprachen durchaus möglich ist:


Dim myBool As Boolean = 2

Das hat natürlich auch Auswirkungen auf Bedingungsprüfungen, wie Sie später noch sehen werden.

Dieser allgemeinste aller Datentypen, Object, beschreibt in seinen vier Byte einen Zeiger auf die Adresse eines Objekts der aktuellen oder einer anderen Anwendung. Eine Variable dieses Typs kann jeden beliebigen anderen Datentypen beschreiben: Ob es sich um einen Integer, einen String, um eine Datenbankverbindung oder um ein anderes spezielles Objekt wie zum Beispiel um eine Schaltfläche handelt, spielt dabei keine Rolle. Zur Laufzeit wird eine auf dem Typ Object basierende Variable passend aufgelöst und die gewünschte Operation darauf ausgeführt. Im folgenden Codefragment wird beispielsweise eine Variable des Typs Object deklariert und anschließend mit einer Ganzzahl initialisiert:


Dim x As Object
x = 3400

Ganz gleich, was eine Variable vom Typ Object beinhaltet, sie enthält grundsätzlich immer nur einen Zeiger (Verweis oder auch Referenz) auf ein Objekt – selbst dann, wenn es sich um eine Zahl handelt, denn die .NET-Laufzeitumgebung kapselt jedes Literal in einem Objekt. Herkömmliche Betriebssysteme beschreiben 32-Bit-Speicheradressen. Daher ergibt sich auch die einheitliche Größe dieses Datentyps von 4 Byte – unabhängig davon, welcher Typ referenziert wird.

Die nativen Datentypen als Objekte

Eine Variable zu deklarieren, sieht so harmlos und unscheinbar aus. Und dennoch, hinter dem Variablennamen verbergen sich Möglichkeiten, die Sie bisher noch nicht ansatzweise erahnt haben. In .NET wird alles durch die objektorientierte Brille betrachtet, sogar die nativen Datentypen.

Ein einfacher Integer soll ein Objekt sein? Wenn Sie dieser Aussage keinen Glauben schenken wollen, dann deklarieren Sie eine Variable vom Typ Integer:


Dim intVariable As Integer

Schreiben Sie dann in der folgenden Zeile:


intVariable.

Beachten Sie, dass hinter dem Variablennamen ein Punkt gesetzt ist. Mit Erstaunen werden Sie feststellen, dass hinter der Punktangabe plötzlich eine Liste aufgeklappt wird – die IntelliSense-Unterstützung (siehe Abbildung 3.4).

In dieser Liste sind alle Eigenschaften und Methoden aufgeführt, die ein Objekt vom Typ Integer auszeichnen. Sie können sich dieser Funktionalitäten bedienen. Wenn Sie beispielsweise wissen wollen, wo die Ober- bzw. Untergrenze des Integers liegt, könnten Sie dies mit dem folgenden Codefragment abfragen:


Sub Main()
Dim intVariable As Integer
Console.WriteLine("Integer(min) = {0}", intVariable.MinValue)
Console.WriteLine("Integer(max) = {0}", intVariable.MaxValue)
Console.ReadLine()
End Sub

Abbildung
Hier klicken, um das Bild zu Vergrößern

Abbildung 3.4     IntelliSense-Liste einer Integervariablen

Beachten Sie bitte hierbei, dass in syntaktisch gleicher Weise, wie Sie die Methode WriteLine der Klasse Console mittels Punktnotation aufrufen, auch auf die Ober- und Untergrenze des Typs Integer zugreifen: zuerst die Angabe des Objektnamens, der in unserem Beispiel intVariable lautet, danach durch einen Punkt abgetrennt die Methode bzw. Eigenschaft (in unserem Fall handelt es sich um eine Eigenschaft).

An der Konsole erfolgt danach die Anzeige:


Integer(min) = –2147483648
Integer(max) = 2147483647


Galileo Computing

3.2.4 Sichtbarkeit und Lebensdauer  downtop

Jede Variable unterliegt einer bestimmten Sichtbarkeit und Lebensdauer. Unter Sichtbarkeit wird verstanden, von welchen Stellen des Programmcodes aus auf eine Variable zugegriffen werden kann. Die Lebensdauer beschreibt, wie lange eine Variable den für sie reservierten Speicherplatz beansprucht und den Inhalt beibehält. Gesteuert werden Sichtbarkeit und Lebensdauer durch die Wahl eines passenden Modifizierers (Dim, Static, Public oder Private) sowie durch die Position der Deklaration.

In diesem Kapitel, das zunächst nur in die grundlegende Sprachsyntax einführt, orientieren wir alle Aussagen und Beispiele nur an Modulen. .NET kennt noch eine weitere, wesentlich wichtigere Codeeinheit: die Klasse. In einer Klasse wird eine Variable anders interpretiert, ihr kommt eine besondere Bedeutung zu. Außerdem müssen in Klassen noch weitere Zugriffsmodifizierer berücksichtigt werden, die bei den herkömmlichen Modulen keine Bedeutung haben. Diese Thematik werden wir im Moment unberücksichtigt lassen und erst in den folgenden beiden Kapiteln beleuchten.

Grundsätzlich können Variablen

gp  innerhalb einer Prozedur eines Moduls
gp  im Allgemeinteil des Moduls

deklariert werden. Im folgenden Codefragment soll dies verdeutlicht werden.


Module Module1
'Variable im Deklarationsbereich des Moduls
Private intVar As Integer
Sub Main()
'Variable innerhalb der Prozedur Main
Dim lngDate As Long
End Sub
Sub UserDefinedProc()
'Variable innerhalb der Prozedur UserDefinedProc
Dim strValue As String
End Sub
End Module

Die Variable intVar ist außerhalb jeglicher Prozedur deklariert – sie befindet sich im Deklarationsabschnitt des Moduls. Ihr Inhalt kann sowohl aus der Prozedur Main heraus gelesen oder verändert werden als auch aus der benutzerdefinierten Prozedur UserDefinedProc. Variablen im Deklarationsabschnitt eines Moduls werden als globale Variablen bezeichnet, weil sie sich (zumindest) im Sichtbarkeitsbereich aller Prozeduren des aktuellen Moduls befinden.

Sowohl innerhalb der Prozedur Main als auch innerhalb der Prozedur UserDefinedProc ist jeweils eine Variable deklariert. Variablen, die innerhalb einer Prozedur deklariert werden, bezeichnet man als lokale Variablen.

Lokale Variablen

Eine Variable, die Sie innerhalb einer Prozedur deklarieren, wird als lokale Variable bezeichnet. Zulässige Zugriffsmodifizierer lokaler Variablen sind nur Dim und Static.

Lokale Variablen zeichnen sich dadurch aus, dass sie nur innerhalb der deklarierenden Prozedur bekannt sind – ihre Sichtbarkeit ist auf diese Prozedur beschränkt. Aus anderen Prozeduren heraus kann weder lesend noch schreibend auf den Inhalt einer lokalen Variablen zugegriffen werden. Außerdem ist durch die Dauer des Prozeduraufrufs auch die Lebensdauer dieser Variablen festgeschrieben. Nach dem Verlassen der Prozedur mit End Sub werden lokale Variablen zerstört und der von ihnen reservierte Speicher wieder freigegeben.

Es gibt jedoch Situationen, da ist Verlust des Inhalts nicht wünschenswert. Angenommen Sie möchten feststellen, wie oft die Prozedur UserDefinedProc während der Laufzeit des Programms ausgeführt wird. Dazu ist ein Zähler notwendig, der bei jedem Prozeduraufruf entsprechend erhöht wird. Eine lokale Variable, die mit dem Modifizierer Dim deklariert ist, kann diese Aufgabe nicht erfüllen, da sie ihren Inhalt mit Beendigung des Prozeduraufrufs verliert. Die Lösung wird durch den Modifizierer Static geboten. Die Inhalte statischer Variablen gehen nach dem Verlassen einer Prozedur nicht verloren, sondern bleiben erhalten. An der Sichtbarkeit ändert sich im Vergleich zu einer mit Dim deklarierten lokalen Variablen nichts, nur die Lebensdauer verlängert sich auf unbestimmte Zeit (genauer gesagt, auf die Laufzeit der Anwendung).

Um das Verhalten einer statischen Variablen zu demonstrieren, enthält das folgende Codefragment zusätzlich zu der Prozedur Main eine weitere, benutzerdefinierte Prozedur namens UserDefinedProc. Aus Main heraus wird die Prozedur UserDefinedProc dreimal aufgerufen. Bei jedem Aufruf wird innerhalb der aufgerufenen Prozedur die statische Variable intCounter um 1 erhöht.


' -------------------------------------------------------
' Beispiel: ...\Kapitel 3\StaticVariable
' -------------------------------------------------------
Module Module1
Sub Main()
'Aufrufe der benutzerdefinierten Prozedur
UserDefinedProc()
UserDefinedProc()
UserDefinedProc()
Console.Read()
End Sub
Sub UserDefinedProc()
'statischer Zugriffszähler
Static intCounter As Integer
intCounter = intCounter + 1
Console.WriteLine("{0}.Prozeduraufruf", intCounter)
End Sub
End Module

Die Ausgabe an der Konsole erfolgt durch eine Anweisung in der benutzerdefinierten Prozedur. Dabei wird der Platzhalter {0} durch den aktuellen Stand der statischen Variablen intCounter ersetzt. Die Ausgabe lautet nach dem Start der Laufzeit:


1.Prozeduraufruf
2.Prozeduraufruf
3.Prozeduraufruf

Würden wir den Modifizierer Static durch Dim ersetzen, würde uns dreimal hintereinander der erste Prozeduraufruf vorgegaukelt.

Globale Variablen

Außerhalb jeglicher Prozedur im Deklarationsteil eines Moduls definierte Variablen werden als global bezeichnet. Die Sichtbarkeit globaler Variablen wird über die Zugriffsmodifizierer gesteuert:

gp  Wird eine globale Variable Private deklariert (oder Dim, was ebenfalls zulässig ist und dieselbe Wirkung hat), kann sie von jeder Prozedur aufgerufen und manipuliert werden, die sich innerhalb des Moduls befindet. Außerhalb des Moduls ist die Variable nicht bekannt. Die Sichtbarkeit ist somit auf das Modul beschränkt.
gp  Wird eine globale Variable Public deklariert, ist sie anwendungsweit bekannt. Der Wert kann von jeder Prozedur gelesen und geändert werden. Dabei spielt es keine Rolle, in welchem Modul sich die Prozedur befindet, aus der heraus der Zugriff erfolgt.

Die lokale, statische Variable intCounter des Projektbeispiels StaticVariable könnte demnach auch durch eine globale ersetzt werden und würde in derselben Weise die an sie gestellten Anforderungen erfüllen. Anders läge der Sachverhalt, würde die Konsolenausgabe aus der Main-Prozedur heraus erfolgen. Dann könnte nur eine globale Zählervariable die an sie gestellte Aufgabe erfüllen – keine weitere Änderung des Programmcodes vorausgesetzt, wie zum Beispiel die Rückgabe des Zählerstands an die aufrufende Prozedur, was auch noch im Bereich der programmiertechnischen Möglichkeiten liegt.


' -------------------------------------------------------
' Beispiel: ...\Kapitel 3\GlobaleVariable
' -------------------------------------------------------
Module Module1
Dim intCounter As Integer
Sub Main()
UserDefinedProc()
Console.WriteLine("{0}.Prozeduraufruf", intCounter)
UserDefinedProc()
Console.WriteLine("{0}.Prozeduraufruf", intCounter)
UserDefinedProc()
Console.WriteLine("{0}.Prozeduraufruf", intCounter)
Console.Read()
End Sub
Sub UserDefinedProc()
intCounter = intCounter + 1
End Sub
End Module

Es gilt als guter Programmierstil, einer Variablen nur die Sichtbarkeit zuzugestehen, die sie im Code auch tatsächlich benötigt. Dahinter verbirgt sich der Gedanke, eine nicht zulässige, unkontrollierte Manipulation auszuschließen. Außerdem gilt es auch zu bedenken, dass globale Variablen dauerhaft Speicherressourcen verbrauchen, was trotz der guten Ausstattung moderner Rechner in großen Anwendungen durchaus ein gewichtiges Argument sein kann.

Überdeckte Variablen

Bezeichner von Variablen müssen grundsätzlich in ihrem direkten Definitionsbereich eindeutig sein. Innerhalb einer Prozedur dürfen beispielsweise nicht zwei gleichnamige Variablen deklariert werden. Dennoch ist es möglich, zwei Variablen mit gleichem Namen zu deklarieren, deren Sichtbarkeitsbereich sich überschneidet. Betrachten Sie dazu das folgende Codefragment:


Module Module1
Public intVar As Integer
Sub Main()
Dim intVar As Integer
...
End Sub
End Module

Auf Modulebene wird die Variable intVar deklariert, eine gleichnamige Variable in der Prozedur Main. Aus der Position der Prozedur heraus sind beide Variablen gleichermaßen sichtbar. Dennoch verursachen sie keinen Mehrdeutigkeitskonflikt, da sie sich in ihrem individuellen Gültigkeitsbereich unterscheiden. Die unabdingbare Eindeutigkeit eines Variablennamens ist somit auch in diesem Fall gewährleistet.

Wenn zwei Variablen denselben Namen, aber einen unterschiedlichen Gültigkeitsbereich haben, wird bei Angabe des Bezeichners auf die Variable zugegriffen, die den kleineren Gültigkeitsbereich aufweist – es ist die lokale. Die lokal deklarierte Variable überdeckt die globale. Soll nun aus der Prozedur heraus, welche die lokale Variante der Variable bereitstellt, auf die gleichnamige globale zugriffen werden, muss der qualifizierende Name der Variablen angegeben werden, beispielsweise:


Module1.intVar

Bei einem qualifizierenden Namen wird vor dem Variablennamen zusätzlich der Name des Moduls angegeben, in dem die globale Variable deklariert ist. Modulname und Variablenname werden durch einen Punkt voneinander getrennt (Punktnotation). Allgemein gültig formuliert sieht die Syntax folgendermaßen aus:


<Modulname>.<Variablenbezeichner>


Galileo Computing

3.2.5 Initialisierung von Variablen  downtop

Nach der Deklaration werden Variablen mit Werten initialisiert, die dem Datentyp entsprechen. Die Initialisierung kann explizit in der Deklarationsanweisung erfolgen, beispielsweise mit:


Public intNewVar As Integer = 9
Dim strMeldung As String = "Visual Studio"

Wird bei der Deklaration einer Variablen nicht explizit ein Datum zugewiesen, wird sie vor-initialisiert. Die folgende Tabelle enthält die Vorinitialisierungswerte der verschiedenen Datentypen.


Tabelle 3.3     Die Vorinitialisierungen der Datentypen

Datentypen Vorinitialisierung
Short, Integer, Long, Single, Double, Decimal, Byte 0
String Leerstring
Boolean False
Object Nothing

Beachten Sie bitte, dass die Vorinitialisierung unabhängig davon ist, ob es sich um eine lokale oder um eine globale Variable handelt.


Galileo Computing

3.2.6 Datentypkonvertierung  downtop

In Visual Basic 2005 können in einem Ausdruck unterschiedliche native Datentypen eingesetzt werden. Das bedeutet, dass die an einer Operation beteiligten Operanden einer Anweisung unterschiedliche Datentypen aufweisen können. In diesem Fall muss vom Compiler eine Typanpassung vorgenommen werden, bei der die beiden Operanden einen gemeinsamen Datentyp für die Operation erhalten. Eine solche Typanpassung wird als Datentypkonvertierung bezeichnet. Dabei werden zwei Arten unterschieden:

gp  Die implizite Konvertierung, bei welcher der kleinere der beiden beteiligten Datentypen in den größeren umgewandelt wird.
gp  Die explizite Konvertierung, bei welcher der größere der beiden Datentypen in den Typ des kleineren überführt wird.

Bei allen Konvertierungen bleibt das Original unverändert.

Implizite Konvertierung

Betrachten Sie zunächst die dritte Zeile des folgenden Codefragments, in welcher der Inhalt einer Variablen vom Typ Integer einer zweiten Variablen, diesmal vom Typ Long, zugewiesen werden soll.


Dim intVar As Integer = 20
Dim lngVar As Long
lngVar = intVar

Um der Variablen vom Typ Long einen Integer-Wert zuzuweisen, ist eine Typumwandlung notwendig, die automatisch vom Compiler durchgeführt und daher als implizite Konvertierung bezeichnet wird. Implizite Konvertierungen setzen immer eine Typaufweitung voraus – der Inhalt eines Integers wird in einen Long gesteckt, der definitionsgemäß einen viel größeren Wertebereich abdeckt.


Bei der impliziten Konvertierung – d.  h. Option Strict On – bleibt die Größe eines Werts grundsätzlich immer erhalten. Die Genauigkeit kann allerdings durchaus Einbußen erleiden.


Die wesentlichsten impliziten Konvertierungen primitiver Datentypen sind der folgenden Abbildung zu entnehmen. Die Pfeilrichtung gibt dabei die Richtung der automatischen Konvertierung vor. Ein Integer darf demzufolge in einen Long, Decimal, Single oder Double umgewandelt werden, ein Single nur in einen Double.

Abbildung
Hier klicken, um das Bild zu Vergrößern

Abbildung 3.5     Implizite Datentypkonvertierung

Eine besondere Stellung nehmen die Datentypen Char, String und Boolean ein. Ein Char-Typ kann implizit nur in einen Integer konvertiert werden, mit einem String bzw. einem Boolean sind keine automatischen Konvertierungen möglich. Variablen vom Typ Object unterliegen Regeln, die auf Voraussetzungen basieren, die erst ab Kapitel 4 erörtert werden.

Mit diesen Regeln werden die folgenden Zuweisungen korrekt implizit konvertiert:


Dim x As Byte = 45, y As Single
y = x
Dim a As Short = 2, b As Decimal
b = a
Dim c As Char = CChar("A"), str As String
str = c

Explizite Konvertierung

Die implizite Konvertierung spielt immer dann eine Rolle, wenn die Typumwandlung eine Aufweitung zur Folge hat. Tritt bei einer Operation jedoch eine Einengung des Typs auf, muss explizit konvertiert werden. Das folgende Codefragment würde also zu einer Fehlermeldung führen, da ein Long mit seiner Größe von 8 Byte doppelt so viel Speicher in Anspruch nimmt wie ein nur vier Byte großer Integer.


Dim lngVar As Long = 20
Dim intVar As Integer
'ACHTUNG : Unzulässige Operation
intVar = lngVar

Um explizit zu konvertieren, haben Sie unter VB 2005 zwei Möglichkeiten:

gp  Sie rufen eine sprachspezifische Konvertierungsfunktion von VB 2005 auf (siehe Tabelle 3.5). Diese gibt es in den anderen .NET-konformen Sprachen nicht.
<
gp  Sie nutzen die Methoden der Klasse Convert der .NET-Klassenbibliothek.